package fch;

import java.awt.Color;
import robocode.BulletHitEvent;
import robocode.HitRobotEvent;
import robocode.HitWallEvent;
import robocode.Rules;
import robocode.ScannedRobotEvent;

/**
 * Moves randomly and tracks an enemy robot with the gun, shooting if it is in range.
 * 
 * @author Christopher Foo
 * 
 */
public class CrazyTracker extends MovingRobot {

  /** The total number of shots fired. */
  private int shot = 0;

  /** The number of bullets that have hit an enemy robot. */
  private int hit = 0;

  @Override
  /**
   * Move to a random point between 50 and 150 pixels away and rotate radar to track enemy robots.
   */
  public void run() {
    setAdjustRadarForGunTurn(true);
    byte signX; // Direction in which X values should change (either +1 or -1)
    byte signY; // Direction in which Y values should change (either +1 or -1)

    // Make the robot white
    setAllColors(Color.white);
    while (true) {

      // Randomize X direction
      if (Math.random() > 0.5) {
        signX = 1;
      }
      else {
        signX = -1;
      }

      // Randomize Y Direction
      if (Math.random() > 0.5) {
        signY = 1;
      }
      else {
        signY = -1;
      }

      // Move to random point within 150 pixels
      moveToPoint((Math.random() * signX * 100) + (50 * signX) + getX(),
          (Math.random() * signY * 100) + (50 * signY) + getY());
      turnRadarRight(360);
    }
  }

  /**
   * Calculates the appropriate power to use on a shot.
   * 
   * @param distance Distance from the target.
   * @param hit The number of shots that have hit a target.
   * @param shot The total number of shots fired.
   * @return The bullet power to be fired or -1 if a bullet should not be fired.
   */
  public double calculatePower(double distance, double hit, double shot) {
    double hitRate = 1; // The percentage of shots that have hit initialize to 1.
    double power = -1; // The power of the shot to fire. Initialize to invalid value of -1.

    // If shots are not 0 (no divide by 0), calculate hit rate.
    if (shot != 0) {
      hitRate = hit / shot;
    }
    // If more than 50% of the shots so far have hit.
    if (hitRate > 0.5) {
      if (distance < 200) {
        power = Rules.MAX_BULLET_POWER;
      }
      else if (distance < 300) {
        power = (Rules.MAX_BULLET_POWER * 2) / 3;
      }
      else if (distance < 500) {
        power = Rules.MAX_BULLET_POWER / 3;
      }
    }

    // If 50% or less of the shots have hit, only shoot at closer distances to improve accuracy.
    else {
      if (distance < 100) {
        power = Rules.MAX_BULLET_POWER;
      }
      else if (distance < 300) {
        power = (Rules.MAX_BULLET_POWER * 2) / 3;
      }
      else if (distance < 400) {
        power = Rules.MAX_BULLET_POWER / 3;
      }
    }

    return power;
  }

  @Override
  /**
   * Increment hit counter when bullet hits an enemy.
   */
  public void onBulletHit(BulletHitEvent event) {
    this.hit++;
  }

  @Override
  /**
   * When a wall is hit, turn around a random amount between 90 and 180 degrees and move forward 
   * between 50 and 100 pixels.
   */
  public void onHitWall(HitWallEvent event) {
    turnRight(Math.random() * 90 + 90);
    ahead(Math.random() * 50 + 50);
  }

  @Override
  /**
   * When another robot is hit, turn around a random amount between 90 and 180 degrees and move
   * forward between 50 and 100 pixels.
   */
  public void onHitRobot(HitRobotEvent event) {
    turnLeft(Math.random() * 90 + 90);
    ahead(Math.random() * 50 + 50);
  }

  @Override
  /**
   * When enemy robot is detected, track it with the gun and fire if it is in range.
   */
  public void onScannedRobot(ScannedRobotEvent event) {
    double power = this.calculatePower(event.getDistance(), this.hit, this.shot);
  
    if (power >= Rules.MIN_BULLET_POWER) {
      
      // Track target with the gun.
      double headingToEnemy = getHeading() + event.getBearing();

      // 0 <= Heading < 360
      if (headingToEnemy >= 360) {
        headingToEnemy = headingToEnemy - 360;
      }
      else if (headingToEnemy < 0) {
        headingToEnemy = headingToEnemy + 360;
      }

      if (Math.round(headingToEnemy) != Math.round(getGunHeading())) {

        double amountToTurn = headingToEnemy - getGunHeading();

        // Large clockwise turn = turn counter-clockwise
        if (amountToTurn > 180) {
          turnGunLeft(360 - amountToTurn);
        }

        // Large counter-clockwise turn = turn clockwise
        else if (amountToTurn < -180) {
          turnGunRight(360 + amountToTurn);
        }
        else {
          turnGunRight(amountToTurn);
        }
      }

      fire(power);
      this.shot++;
    }
  }
}
